# _*_ coding:utf-8 _*_
__all__ = ['dict2Html', 'df2Html']

'''
参考设计：
    pandas.DataFrame.to_html https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.to_html.html
'''

import os, sys
curdir = os.path.dirname(os.path.abspath(__file__))
sys.path.append(curdir)
import numpy
import math
import StrUtils
from SR_Context import SR_Context
import MiscUtils

sr_default_style = '''
<style>
.sr_default_style {
    font-size: 11pt;
    font-family: Arial;
    border-collapse: collapse;
    border: 1px solid silver;
}
.sr_default_style td, th {
    padding: 5px;
}
.sr_default_style tr:nth-child(even) {
    background: #E0E0E0;
}
.sr_default_style tr:hover {
    background: silver;
    cursor: pointer;
}
</style>
'''

def calStatesTable(dict_, valNone='x'):
    numX = 0
    numY = 0
    for key, val in dict_.items():
        if key > numY:
            numY = key

        len0 = len(val)
        if len0 > numX:
            numX = len0

    numY += 1
    countRec = numpy.zeros([numY, numX])

    # 通过给空值引入噪音，使得它不参与格子的合并。
    noise = 1
    for x in range(numX):
        y = numY - 1
        while (y > 0):
            itemThisStr = ''
            try:
                status, s = StrUtils.getStatementContent(dict_[y][x], True, valNone)
                status, itemThisStr = StrUtils.getStatementContent(s, False, valNone)
            except (IndexError, KeyError):
                itemThisStr = '\0' + str(noise)
                noise += 1

            itemUpperStr = ''
            try:
                status, s = StrUtils.getStatementContent(dict_[y-1][x], True, valNone)
                status, itemUpperStr = StrUtils.getStatementContent(s, False, valNone)
            except (IndexError, KeyError):
                itemUpperStr = '\0' + str(noise)
                noise += 1

            if (itemThisStr == itemUpperStr):
                if (x == 0):
                    countRec[y-1][x] += (countRec[y][x] + 1)
                    countRec[y][x] = 0
                else:
                    if (countRec[y][x-1] == 0):
                        countRec[y-1][x] += (countRec[y][x] + 1)
                        countRec[y][x] = 0
                    else:
                        countRec[y][x] += 1
            else:
                countRec[y][x] += 1

            y -= 1
        x += 1

    for i in range(numX):
        countRec[0][i] += 1

    return numY, numX, countRec


def dict2Html(_src, dict_=None, valNone='x', id_='sr', css_class='sr_default_style', css_style='',
                numFormatStr="{:.2f}", src_moredata=False, dataSep=' ', fmtYtitle=True, hideFlag='*'):
    '''
    src_moredata: data, moredata, all
    fmtYtitle: 行标题内容显示格式，False或0：不显示； 1：显示序号；True：显示内容
    '''

    def hideDictItems(hideFlag, dict_, valNone):
        #遍历_src_titlesY、_src_titlesX中的元素，把需要hide的key隐藏
        if hideFlag:
            if isinstance(valNone, str):
                hideFlag2 = valNone + hideFlag
            else:
                hideFlag2 = '\0'
        else:
            hideFlag = '\0'
            hideFlag2 = '\0'

        for key in list(dict_):
            values = dict_.get(key)
            for value in values:
                try:
                    # statemend // comment_1 //comment_2
                    #              ^_________
                    status, val = StrUtils.getStatementContent(value, True, valNone)
                    status, val = StrUtils.getStatementContent(val, False, valNone)
                except (IndexError, KeyError):
                    val = valNone
                if val.startswith(hideFlag) or val.startswith(hideFlag2):
                    del dict_[1]
                    break


    if not css_style:
        css_style = sr_default_style

    retStr = css_style + '<table width="100%" border="1" class="' + css_class + '" id="' + id_ + '">'
    if dict_:
        # for test this function
        if hideFlag:
            #遍历_src_titlesY、_src_titlesX中的元素，把需要hide的key隐藏
            hideDictItems(hideFlag, dict_, valNone)

        y_numY, y_numX, y_lines = dict2lines(dict_, 'y', 0, valNone, hideFlag)
        x_numY, x_numX, x_lines = dict2lines(dict_, 'x', y_numX, valNone, hideFlag)
        _src_titlesY = dict_
        _src_titlesX = dict_
    else:
        _src_titlesY = _src.titlesY.copy()
        _src_titlesX = _src.titlesX.copy()

        if hideFlag:
            #遍历_src_titlesY、_src_titlesX中的元素，把需要hide的key隐藏
            hideDictItems(hideFlag, _src_titlesY, valNone)
            hideDictItems(hideFlag, _src_titlesX, valNone)

        y_numY, y_numX, y_lines = dict2lines(_src_titlesY, 'y', 0, valNone, hideFlag)
        if fmtYtitle:
            x_numY, x_numX, x_lines = dict2lines(_src_titlesX, 'x', y_numX, valNone, hideFlag)
        else:
            x_numY, x_numX, x_lines = dict2lines(_src_titlesX, 'x', 0, valNone, hideFlag)
            y_lines = ['<tr style="text-align:center;">'] * y_numY

    retStr += '<thead>'
    retStr += ''.join(x_lines)
    retStr += '</thead>'

    if src_moredata:
        data = _src.moredata
    else:
        data = _src.data

    for i in range(y_numY):
        if hideFlag:
            if not _src_titlesY.get(i):
                continue

        for j in range(x_numX):
            if hideFlag:
                if not _src_titlesX.get(j):
                    continue

            val = ''
            try:
                val = data[i][j]
                if (src_moredata == 'all') and (not val):
                    val = _src.data[i][j]
            except (IndexError, KeyError):
                val = valNone

            if isinstance(val, float):
                if math.isnan(val):
                    y_lines[i] += '<td></td>'
                else:
                    y_lines[i] += '<td>' + numFormatStr.format(val) + '</td>'
            elif isinstance(val, (list, tuple)):
                arr_0 = []
                for x in val:
                    x = MiscUtils.spread(x)
                    if isinstance(x, float):
                        if math.isnan(x):
                            arr_0.append('')
                        else:
                            arr_0.append(numFormatStr.format(x))
                    else:
                        arr_0.append(str(x))
                y_lines[i] += '<td>' + dataSep.join(arr_0) + '</td>'
            else:
                if StrUtils.isEmpty(val):
                    y_lines[i] += '<td></td>'
                else:
                    y_lines[i] += '<td>' + str(val) + '</td>'
        y_lines[i] += '</tr>\n'
    retStr += ''.join(y_lines)
    retStr += '</table>\n'
    return retStr


def dict2lines(dict_, x_y='y', leftSpan=0, valNone='x', hideFlag=''):
    numY, numX, countRec = calStatesTable(dict_, valNone)

    if (x_y == 'y'):
        lines_ = [''] * numY
        for i in range(numY):
            if dict_.get(i):
                lines_[i] = '<tr style="text-align:center;">'
            else:
                if hideFlag:
                    lines_[i] = ''
                    continue

            for j in range(numX):
                if (countRec[i,j] > 1):
                    val = ''
                    try:
                        # statemend // comment_1 //comment_2
                        #              ^_________
                        status, val = StrUtils.getStatementContent(dict_[i][j], True, valNone)
                        status, val = StrUtils.getStatementContent(val, False, valNone)
                    except (IndexError, KeyError):
                        val = valNone
                    lines_[i] += '<th rowspan="' + str(countRec[i,j]) + '">' + val + '</th>'
                else:
                    if (countRec[i,j] > 0):
                        val = ''
                        try:
                            # statemend // comment_1 //comment_2
                            #              ^_________
                            status, val = StrUtils.getStatementContent(dict_[i][j], True, valNone)
                            status, val = StrUtils.getStatementContent(val, False, valNone)
                        except (IndexError, KeyError):
                            val = valNone
                        lines_[i] += '<th>' + val + '</th>'
            #行标题，可能会在后一环节加</tr>
            #lines_[i] += '</tr>'
        return numY, numX, lines_

    lines_ = [''] * numX
    for i in range(numX):
        lines_[i] = '<tr style="text-align:center;">'

        if (leftSpan > 0) and (i == 0):
            lines_[i] += '<th colspan="' + str(leftSpan) + '" rowspan="' + str(numX) + '"></th>'

        for j in range(numY):
            if hideFlag:
                if not dict_.get(j, ''):
                    continue

            if (countRec[j,i] > 1):
                val = ''
                try:
                    # statemend // comment_1 //comment_2
                    #              ^_________
                    status, val = StrUtils.getStatementContent(dict_[j][i], True, valNone)
                    status, val = StrUtils.getStatementContent(val, False, valNone)
                except (IndexError, KeyError):
                    val = valNone
                lines_[i] += '<th colspan="' + str(countRec[j,i]) + '">' + val + '</tdh>'
            else:
                if (countRec[j,i] > 0):
                    val = ''
                    try:
                        # statemend // comment_1 //comment_2
                        #              ^_________
                        status, val = StrUtils.getStatementContent(dict_[j][i], True, valNone)
                        status, val = StrUtils.getStatementContent(val, False, valNone)
                    except (IndexError, KeyError):
                        val = valNone
                    lines_[i] += '<th>' + val + '</th>'
        lines_[i] += '</tr>\n'
    return numX, numY, lines_


def df2Html(df, id_='sr', css_class='sr_default_style', css_style='', numFormatStr="{:.2f}"):
    _src = SR_Context()

    dict_y = {}
    for i, item in enumerate(df.index.to_list()):
        if isinstance(item, (int, float, str)):
            dict_y[i] = [item]
        else:
            dict_y[i] = item

    dict_x = {}
    for i, item in enumerate(df.columns.to_list()):
        if isinstance(item, (int, float, str)):
            dict_x[i] = [item]
        else:
            dict_x[i] = item

    _src.titlesY = dict_y
    _src.titlesX = dict_x
    _src.data = df.values

    retStr = dict2Html(_src, None, valNone='', id_=id_, css_class=css_class, css_style=css_style, numFormatStr=numFormatStr)
    return retStr


if __name__ == '__main__':
    _src = SR_Context()
    ''' test_1    '''
    dict_ = {1: ['Y1, X0', 'Y1, X1', 'Y1, X2'],
        2: ['*Y2, X0', 'Y2, X1', 'Y2, X2'],
        3: ['Y3, X0', 'Y3, X1', 'Y3, X2'],
        4: ['Y3, X0', 'Y5, X1', 'Y4, X2'],
        5: ['Y3, X0', 'Y5, X1', 'Y5, X2'],
        8: ['Y6, X0', 'Y6, X1', 'Y6, X2']}
    print (dict_)

    retStr = dict2Html(_src, dict_, '.', hideFlag='*')
    print (retStr)


    '''test_2
    import sample_data
    demo_df_ = sample_data.demo_df()
    demo_df_ = demo_df_.set_index(['os', 'database']).sort_index()
    retStr = df2Html(demo_df_)

    print (retStr)
    '''
